<template>
    <div class="app-container">
        <el-input v-model="filterText" placeholder="Filter keyword" style="margin-bottom:30px;" />

        <sticky :z-index="10">
            <el-card :class="cardClass">
                <svg-icon :icon-class="buttonSvg" class-name="float-button" @click="switchCard" />
                <div v-show="showCard" v-if="hasChecked" slot="header">
                    <span>批量更新</span>
                </div>
                <template v-show="showCard" slot="default">
                    <batch-operation
                        v-if="hasChecked"
                        :checked-keys="checkedKeys"
                        :checked-nodes="checkedNodes"
                        @batch-delete="handleBatchDelete"
                        @batch-display="handleBatchDisplay"
                        @batch-hide="handleBatchHide"
                    />
                    <category-form
                        v-else
                        :cascade-options="cascadeTree"
                        :affiliate-list="categoryAffiliate"
                        :category-props="currentCategory"
                        @card-submit="handleCardSubmit"
                        @node-create="handleNodeCreate"
                        @node-delete="handleNodeDelete"
                        @tree-refresh="fetchTreeData"
                    />
                </template>
            </el-card>
        </sticky>

        <el-tree
            ref="tree"
            v-loading="treeLoading"
            :data="treeData"
            :props="defaultProps"
            :filter-node-method="filterNode"
            node-key="id"
            class="filter-tree"
            default-expand-all
            :draggable="treeDraggable"
            show-checkbox
            :allow-drop="allowDrop"
            :expand-on-click-node="false"
            @check="handleChecked"
            @node-drag-start="handleDragStart"
            @node-drag-over="handleDragOver"
            @node-drag-end="handleDragEnd"
            @current-change="handleNodeChange"
        >
            <span
                slot-scope="{ node }"
                :style="nodeStyle(node)"
            >
                <span>{{ node.label }}</span>
            </span>
        </el-tree>
    </div>
</template>

<script>
import CategoryForm from '@/views/category/tree/components/category-form'
import BatchOperation from '@/views/category/tree/components/batch-operation'
import { changeCategoryOrder, getCategoryTree } from '@/api/category'
import Sticky from '@/components/Sticky/index'
export default {
    name: 'CategoryTree',
    components: { Sticky, BatchOperation, CategoryForm },
    data() {
        return {
            // 控制卡片收缩
            cardClass: 'float-card min',
            buttonSvg: 'fullscreen',
            isCardExpanded: false,
            showCard: false,

            // 控制卡片数据
            currentCategory: {
                id: 0,
                name: 'none',
                isLeaf: false,
                status: 1
            },

            // 批量操作
            hasChecked: false,
            checkedKeys: [],
            checkedNodes: [],

            // 大类树
            filterText: '',
            isDragging: false,
            treeLoading: false,
            treeDraggable: true,
            treeData: [{
                id: 1,
                name: '学院概况',
                status: 1,
                hasPost: false,
                children: [
                    {
                        name: '组织机构',
                        id: 2,
                        status: 0,
                        hasPost: true
                    }
                ]
            }],

            defaultProps: {
                children: 'children',
                label: 'name',
                disabled: '_disabled'
            },

            // 控制节点样式
            draggingNodeId: undefined, // 正在拖拽的节点
            hoverNodeId: undefined // 拖拽时候对应悬浮的节点
        }
    },
    computed: {
        // 获取不含大类叶子节点的大类树
        cascadeTree() {
            const _currentId = this.currentCategory.id
            const iteration = function(arr) {
                const newArr = []
                if (arr !== undefined && arr.length > 0) {
                    arr.forEach(item => {
                        if (!item.hasPost) {
                            const newItem = {}
                            newItem.name = item.name
                            newItem.id = item.id
                            // 如果与该大类id相同,则设置为不可选
                            if (newItem.id === _currentId) {
                                newItem.disabled = true
                            } else if (item.children !== undefined && item.children.length > 0) {
                                // 递归 遍历子节点
                                const cList = iteration(item.children)
                                if (cList && cList.length > 0) { newItem.children = cList }
                            }
                            newArr.push(newItem)
                        }
                    })
                }
                return newArr
            }
            return iteration(this.treeData)
        },
        // 根据id获取其父级路径
        categoryAffiliate() {
            const _currentId = this.currentCategory.id
            const findIndexArray = (arr, indexArray = []) => {
                const newArr = Array.from(indexArray) // 浅拷贝
                for (let i = 0; i < arr.length; ++i) {
                    const item = arr[i]
                    newArr.push(item.id)
                    if (item.id === _currentId) {
                        return newArr
                    }
                    if (item.children && item.children.length > 0) {
                        const result = findIndexArray(item.children, newArr)
                        if (result) return result
                    }
                    newArr.pop()
                }
                return false
            }
            const rtnArr = findIndexArray(this.treeData)
            return rtnArr ? rtnArr.slice(0, rtnArr.length - 1) : []
        }
    },
    watch: {
        filterText(val) {
            this.$refs.tree.filter(val)
        }
    },
    created() {
        this.fetchTreeData()
    },

    methods: {
        fetchTreeData() {
            this.treeLoading = true
            getCategoryTree().then(data => {
                this.treeData = data
                this.treeLoading = false
            })
        },
        switchCard() {
            this.isCardExpanded = !this.isCardExpanded
            if (this.isCardExpanded) {
                this.cardClass = 'float-card'
                this.buttonSvg = 'exit-fullscreen'
                setTimeout(() => { this.showCard = true }, 200)
            } else {
                this.showCard = false
                this.cardClass = 'float-card min'
                this.buttonSvg = 'fullscreen'
            }
        },

        filterNode(value, data) {
            if (!value) return true
            return data.name.indexOf(value) !== -1
        },
        // 不允许排序, 有文章的category不允许插入其余category节点
        allowDrop(draggingNode, dropNode, type) {
            if (dropNode.data.hasPost) {
                return type !== 'inner'
            } else {
                return true
            }
        },
        handleDragStart() {
            this.isDragging = true
        },
        handleDragEnd(draggingNode, dropNode, dropType, ev) {
            this.isDragging = false
            const _data = {
                id: draggingNode.data.id,
                pid: undefined,
                childrenOrder: null
            }
            if (dropType === 'inner') {
                _data.pid = dropNode.data.id
                _data.childrenOrder = dropNode.data.children.map(data => data.id)
            } else {
                // 更新为1级大类
                if (dropNode.level === 1) {
                    _data.pid = 0
                    _data.childrenOrder = dropNode.parent.data.map(data => data.id)
                } else {
                    _data.pid = dropNode.parent.data.id
                    _data.childrenOrder = dropNode.parent.data.children.map(data => data.id)
                }
            }
            // 上传更新数据
            this.treeDraggable = false
            changeCategoryOrder(_data).then(() => {
                this.treeDraggable = true
                this.$message.success('更新顺序成功!')

                // 如果移动的节点是一级大类, 且移动后改变等级, 则需提示导航条消失
                if (draggingNode.level === 1 && _data.pid !== 0) {
                    this.$notify({
                        title: '警告',
                        type: 'warning',
                        dangerouslyUseHTMLString: true,
                        message: '大类: <strong>' + draggingNode.data.name + ' ' + draggingNode.data.id +
                        '</strong><br>不再为一级大类 将在<strong>导航栏设置</strong>中隐藏',
                        duration: 10000
                    })
                }
            }).catch(() => {
                this.treeDraggable = true
                this.$message.error('顺序更新失败!')
            })
        },
        // 当点击选中对应卡片时
        handleNodeChange(data) {
            // 如果卡片没张开 则打开卡片
            if (!this.isCardExpanded) {
                this.switchCard()
            }
            this.currentCategory = {
                id: data.id,
                name: data.name,
                isLeaf: data.hasPost,
                status: data.status
            }
        },
        // 处理大类树加载
        handleCardSubmit(data) {
            const _tree = this.$refs.tree
            const _data = _tree.getNode(data.id).data
            _data.name = data.name
            _data.status = data.status
            // 如果大类层级关系发生改变
            if (data.hasParentChange) {
                _tree.remove(_data)
                if (data.affiliate.length === 0) {
                    _tree.insertAfter(_data, this.treeData[this.treeData.length - 1])
                } else {
                    _tree.append(_data, data.affiliate[data.affiliate.length - 1])
                }
            }
        },
        // 处理新增节点
        handleNodeCreate(data) {
            const _tree = this.$refs.tree
            const _data = data.node_data
            if (data.parent_id === 0) {
                _tree.insertAfter(_data, this.treeData[this.treeData.length - 1])
            } else {
                _tree.append(_data, data.parent_id)
            }
            this.$message.success('新增大类成功! 已添加至大类树')
        },
        // 处理删除节点
        handleNodeDelete(id) {
            const _tree = this.$refs.tree
            _tree.remove(id)
            // 关闭卡片
            this.switchCard()
            // 重新获取数据
            this.fetchTreeData()
        },

        // 当多选框被选中时
        handleChecked(data, { checkedKeys, checkedNodes }) {
            data // 当前节点数据
            const _hasChecked = checkedKeys.length > 0
            // 判断是否需要切换卡片
            if (!_hasChecked && this.isCardExpanded) {
                this.switchCard()
                // 延时切换
                setTimeout(() => { this.hasChecked = _hasChecked }, 200)
            } else if (_hasChecked && !this.isCardExpanded) {
                // 同步切换
                this.hasChecked = _hasChecked
                this.switchCard()
            } else {
                this.hasChecked = _hasChecked
            }
            this.checkedKeys = checkedKeys
            this.checkedNodes = checkedNodes
        },

        // 批量操作节点
        handleBatchDelete(keys) {
            keys.forEach(id => this.$refs.tree.remove(id))
            this.$message.success('批量删除成功!')
            this.checkedKeys = []
            this.checkedNodes = []

            // 关闭卡片
            this.switchCard()
            this.hasChecked = false // 切换为单大类信息详情模式
        },
        handleBatchDisplay(keys) {
            keys.forEach(id => {
                this.$refs.tree.getNode(id).data.status = 1
            })
            this.$message.success('批量显示设置成功!')
        },
        handleBatchHide(keys) {
            keys.forEach(id => {
                this.$refs.tree.getNode(id).data.status = 0
            })
            this.$message.success('批量隐藏设置成功!')
        },

        handleDragOver(node, nodeTo) {
            this.draggingNodeId = node.data.id
            this.hoverNodeId = nodeTo.data.id
        },

        // 节点样式方法
        nodeStyle(node) {
            const data = node.data
            const level = node.level
            return {
                fontSize: '18px',
                color: data.status === 0 || (data.hasPost && this.isDragging) ? '#C0C4CC' : '',
                fontWeight: level === 1 ? '450' : '400',
                background: data.id === this.hoverNodeId && data.id !== this.draggingNodeId &&
                !data.hasPost && this.isDragging ? 'rgb(217, 236, 255)' : ''
            }
        }

    }

}
</script>
<style>
.app-container{
    padding: 20px 40px 20px;
}
.el-tree{
    background: white url("../../../assets/background/pic1.png") no-repeat fixed center;
    background-size: 200px;
}
.el-tree-node__content{
    height: 30px;
}

</style>
